package engine.exitcriteria;

import java.util.Collections;
import java.util.logging.Level;
import java.util.logging.Logger;

import engine.ObjectiveFunction;
import engine.Population;
import engine.TerminationCondition;
import engine.individuals.util.IndividualsComparator;

public class NoImprovementTerminationCondition<T> implements
		TerminationCondition<T> {

	private static final Logger LOGGER = Logger
	.getLogger(NoImprovementTerminationCondition.class.getName());
	
	private int maxIterNoImprovement = 15;
	private int currentIterNoImprovement = 0;
	
	private T prevMax = null;

	private IndividualsComparator<T> indComp;
	
	public NoImprovementTerminationCondition(ObjectiveFunction<T> objFun) {
		this.indComp = new IndividualsComparator<T>(objFun);
	}
	
	public NoImprovementTerminationCondition(
			int maxIterNoImprovement, 
			ObjectiveFunction<T> objFun) {
		
		this(objFun);
		this.maxIterNoImprovement = maxIterNoImprovement; 
	}
	
	@Override
	public boolean isSatisfied(Population<T> population) {

		boolean terminate = false;

		T currentMaxInd = Collections.max(population.getIndividuals(), indComp);

		if (prevMax == null) {
			prevMax = currentMaxInd;
		} else {
			if (indComp.compare(currentMaxInd, prevMax) <= 0) {
				if (++currentIterNoImprovement >= maxIterNoImprovement) {
					terminate = true;
					logEndingMessage();
				}
			} else {
				prevMax = currentMaxInd;
				currentIterNoImprovement = 0;
			}
		}
		return terminate;
	}

	private void logEndingMessage() {
		if (LOGGER.isLoggable(Level.INFO)) {
			StringBuilder builder = new StringBuilder();
			builder.append("No improvement after ");
			builder.append(maxIterNoImprovement);
			builder.append(" iterations. Exiting.");
			LOGGER.info(builder.toString());
		}
	}

}
